package com.smallrig.extension.statemachine.builder;


import com.smallrig.extension.statemachine.Action;
import com.smallrig.extension.statemachine.Condition;
import com.smallrig.extension.statemachine.State;
import com.smallrig.extension.statemachine.Transition;
import com.smallrig.extension.statemachine.impl.StateHelper;
import com.smallrig.extension.statemachine.impl.StateMachineException;
import com.smallrig.extension.statemachine.impl.TransitionType;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


class TransitionBuilderImpl<S,E,C> implements ExternalTransitionBuilder<S,E,C>, InternalTransitionBuilder<S,E,C>, From<S,E,C>, On<S,E,C>, To<S,E,C> {

    private List<State<S, E, C>> sources = new ArrayList<>();

    private List<Transition<S, E, C>> transitions = new ArrayList<>();

    final Map<S, State<S, E, C>> stateMap;

    protected State<S, E, C> target;

    final TransitionType transitionType;

    public TransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) {
        this.stateMap = stateMap;
        this.transitionType = transitionType;
    }

    @Override
    public From<S, E, C> from(S... stateIds) {
        for(S stateId : stateIds) {
            sources.add(StateHelper.getState(stateMap, stateId));
        }
        return this;
    }

    @Override
    public To<S, E, C> to(S stateId) {
        target = StateHelper.getState(stateMap, stateId);
        return this;
    }

    @Override
    public To<S, E, C> within(S... stateIds) {
        for(S stateId : stateIds) {
            sources.add(StateHelper.getState(stateMap, stateId));
        }
        return this;
    }

    @Override
    public When<S, E, C> when(Condition<C> condition) {
        for(Transition transition : transitions){
            transition.setCondition(condition);
        }
        return this;
    }

    @Override
    public On<S, E, C> on(E event) {

        for(State source : sources) {
            Transition transition = source.addTransition(event, target!=null?target:source, transitionType);
            transitions.add(transition);
        }

        return this;
    }


    @Override
    public void perform(Action<S, E, C> action) {
        for(Transition transition : transitions){
            transition.setAction(action);
        }
    }


}
